home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The 640 MEG Shareware Studio 5
/
The 640 Meg Shareware Studio CD-ROM Volume V (Data Express)(1994).ISO
/
amiga
/
tndbrgcn.lha
/
TandbergConf.c
< prev
Wrap
C/C++ Source or Header
|
1994-02-23
|
14KB
|
656 lines
/*
***** TandbergConf
*
* A utility to configure Tandberg TDC3600 SCSI Tape drives.
*
* - Turn on/off Auto retension
* - Settings can be permanant or will reset after a re-boot/power on
*
* Note:
* This code was hacked from an excellent program called SCSIutil,
* written by Gary Duncan (gduncan@philips.oz.au), modified by
* Heiko Rath (hr@brewhr.swb.de)
*
* Information on how to program the TDC3600 was provided by Goncal
* Badenes (badenes@imec.be)
*
* Program returns:
* 1 - init didn't work (maybe allocmem failed, etc.)
* 2 - wrong parameter count
* 3 - wrong parameter
*
*/
#define VERSION "1.0"
/*
**** Includes
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <exec/types.h>
#include <exec/io.h>
#include <exec/execbase.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <devices/trackdisk.h>
#include <devices/scsidisk.h>
#include <dos/rdargs.h>
#include <libraries/dos.h>
#ifdef __SASC
#include <proto/all.h>
#endif
#include "scsi_priv.h"
/*
**** Global variables
*/
UBYTE *scsi_data = NULL;
UBYTE *dev = "";
int scsi_id = -1; /* ID of the SCSI device to send commands to */
UBYTE *pname;
UBYTE buffer[LINE_BUF];
int secno = -1;
MSGPORT *mp_ptr;
IOSTDREQ *io_ptr;
SCSICMD scsi_cmd;
UBYTE *scsi_sense;
UBYTE scsi_status;
/*
**** Function descr.
*/
int breakcheck (void);
int DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags, BOOLEAN);
UBYTE *err_str (int err);
void exit (int status);
UBYTE *GetDevName (char *grep);
BOOLEAN init (void);
void inquiry (void);
void mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page);
void rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace);
UBYTE *sense_errs (int req, int err);
void usage (void);
void write_mode(BOOLEAN, UBYTE *, int);
void parse_mode(void);
#ifdef __SASC
void __regargs __chkabort (void);
#endif /* __SASC */
#define RAW ra_array[2]
#define RETENSION ra_array[3]
#define AUTOLOAD ra_array[4]
#define SAVE ra_array[5]
#define QUIET ra_array[6]
/*********************************************************************
*
* main
*
*
*/
int
main (int argc, char **argv)
{
long ra_array[7] = {0,0,0,0,0,0,0};
struct RDArgs *ra;
static UBYTE cmd_data[24];
int returnvalue = 0;
if (argc == 1)
{
usage ();
exit (1);
}
ra = ReadArgs("UNIT/N/R,DEVICE/K,RAW/S,RETENSION/S,AUTOLOAD/S,SAVE/S,QUIET/S", ra_array, NULL);
if (!ra) {
usage();
return 3;
}
/*
* see if a SCSI.device specified
*/
if (ra_array[1])
dev = (char *)ra_array[1];
else if ((dev = GetDevName (SCSI_STRING)) == NULL)
{
fprintf (stderr, "Error : no *scsi*.device in device list\n");
returnvalue = 1;
goto error;
}
pname = argv[0];
scsi_id = *(long *)ra_array[0];
/*
* now set up structures etc for SCSI xfer
*/
if (init () == FALSE)
{
returnvalue = 1;
goto error;
}
mode_sense(FALSE,0,0);
inquiry();
if (strncmp(&scsi_data[8], "TANDBERG", 8)) {
fprintf(stderr, "Device not a Tandberg drive!\n");
returnvalue = 2;
goto error;
}
/*
* read the mode sense data. We do this twice due to the fact that for some
* reason, the first one fails.
*/
mode_sense(FALSE,0,0);
mode_sense(TRUE,0,0);
if (!QUIET) {
printf("Current Configuration:\n");
if (RAW)
rawhexasciioutput(scsi_data, scsi_data[0]+1, 0);
else
parse_mode();
}
if (RETENSION | AUTOLOAD) {
memcpy(cmd_data, scsi_data,24);
cmd_data[0] = 0x00;
cmd_data[1] = 0x00;
if (RETENSION)
cmd_data[22] = 0x01;
if (AUTOLOAD)
cmd_data[22] = 0x00;
if(SAVE)
write_mode(TRUE, cmd_data, 24);
else
write_mode(FALSE, cmd_data, 24);
if (!QUIET) {
mode_sense(TRUE,0,0);
printf("New Configuration:\n");
if (RAW)
rawhexasciioutput(scsi_data, scsi_data[0]+1, 0);
else
parse_mode();
}
}
error:
FreeArgs(ra);
if (io_ptr)
{
CloseDevice ((struct IORequest *) io_ptr);
DeleteStdIO (io_ptr);
}
if (mp_ptr)
DeletePort (mp_ptr);
if (scsi_sense)
FreeMem (scsi_sense, SENSE_LEN);
if (scsi_data)
FreeMem (scsi_data, MAX_DATA_LEN);
exit (returnvalue);
}
/*********************************************************************
* DWL
* function to write mode select info to a Tandberg drive
*/
void
write_mode(BOOLEAN permanant, UBYTE *cmd_data, int cmd_data_len)
{
static SCSICMD6 command =
{
0x15,/* 0x15 MODE SELECT scsi command */
0, /* LUN | rsrvd. | DBD | rsrvd. */
0, /* PC | Page Code */
0, /* rsrvd. */
0x00, /* allocation length */
0x00 /* control */
};
/* static __chip UBYTE cmd_data[24] = {
0,0,0x10,8,0x10,0,0,0,0,0,2,0,0,2,2,0x78,0,0,8,0,0,0,0,0x64
}; */
int err;
if (permanant)
command.control = 0x40;
else
command.control = 0x00;
command.b4 = cmd_data_len;
if ((err = DoScsiCmd ((UBYTE *) cmd_data, cmd_data_len,
(UBYTE *) &command, sizeof (command),
(SCSIF_WRITE | SCSIF_AUTOSENSE), TRUE)) != 0)
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
}
}
/*********************************************************************
*
* Initialization function
*
*/
BOOLEAN
init (void)
{
if ((scsi_data = (UBYTE *) AllocMem (MAX_DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
{
fprintf (stderr, "AllocMem(0) Fail\n");
return FALSE;
}
if ((scsi_sense = (UBYTE *) AllocMem (SENSE_LEN, MEMF_CHIP || MEMF_CLEAR)) == NULL)
{
fprintf (stderr, "AllocMem (scsi_sense) Fail\n");
return FALSE;
}
if ((mp_ptr = (MSGPORT *) CreatePort (NULL, 0)) == NULL)
{
fprintf (stderr, "CreatePort (mp_ptr) Fail\n");
return FALSE;
}
if ((io_ptr = (IOSTDREQ *) CreateStdIO (mp_ptr)) == NULL)
{
fprintf (stderr, "CreateStdIO (io_ptr) Fail\n");
return FALSE;
}
if (OpenDevice (dev, scsi_id, (struct IORequest *) io_ptr, 0) != 0)
{
fprintf (stderr,
"Error %d while opening SCSI dev \"%s\", unit (%d)\n",
io_ptr->io_Error, dev, scsi_id);
return FALSE;
}
return TRUE;
}
/*********************************************************************
*
* function to read parameter pages from a device
*/
void
mode_sense (BOOLEAN error_chk, UBYTE control, UBYTE page)
{
static SCSICMD6 command =
{
SCSI_CMD_MSE, /* 0x1a MODE SENSE scsi command */
PAD, /* LUN | rsrvd. | DBD | rsrvd. */
0, /* PC | Page Code */
PAD, /* rsrvd. */
0, /* allocation length */
PAD /* control */
};
int err;
command.b2 = (control<<6) | page;
command.b4 = MAX_DATA_LEN;
err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
(UBYTE *) &command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE), error_chk);
if (err != 0) {
if (error_chk)
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
}
}
/*********************************************************************
*
* subroutine used to printout raw hex data bytes with the
* corresponding ASCII values and an index
*
*/
void
rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace)
{
UWORD i, j;
UBYTE *boff, *aoff;
int xxxlen = strlen (" xx"); /* byte */
buffer[5+leadspace] = '=';
for (i = 0; i < numbytes; i += BYTES_PER_LINE)
{
memset (buffer, ' ', sizeof (buffer)); /* put spaces in buffer */
boff = &buffer[7+leadspace];
aoff = boff + (xxxlen * BYTES_PER_LINE) + 1;
sprintf (buffer+leadspace, "%04X = ", i); /* add offset */
for (j = 0; (j < BYTES_PER_LINE && (i+j) < numbytes); j++, boff += xxxlen, p++, aoff++)
{
sprintf (boff, " %02X", *p);
*aoff = (isascii (*p) && isprint (*p)) ? *p : '.';
}
buffer[strlen (buffer)] = ' ';
*++aoff = '\n';
*++aoff = '\0';
printf ("%s", buffer);
}
}
/*********************************************************************
*
* function to make an inquiry
*
*/
void
inquiry ()
{
static SCSICMD6 command =
{
SCSI_CMD_INQ, /* 0x12 INQUIRY */
PAD, /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
PAD, /* Page Code */
PAD, /* Reserved */
0, /* Allocation length */
PAD /* Control */
};
int err;
command.b4 = MAX_DATA_LEN; /* Allocation length = max. data length */
if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
(UBYTE *) & command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE), TRUE)) != 0)
fprintf (stderr, "Inquiry Error : err=%ld , %s\n", err, sense_errs (0, err));
}
/*********************************************************************
*
* searches DeviceList for a device name with a given string in it.
* - if found returns with a pointer to it, else NULL
*/
extern struct ExecBase *SysBase;
UBYTE *
GetDevName (char *grep)
{
LIST *lh = (LIST *) SysBase->DeviceList.lh_Head;
NODE *ln;
for (ln = lh->lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
{
UBYTE *p = ln->ln_Name;
while (*p != '.')
{
if (strncmp (p, grep, 4) == 0)
{
return (ln->ln_Name);
}
++p;
}
}
return (NULL); /* not found */
}
/*********************************************************************
*
* Break (^C) function
*
*/
int
breakcheck (void)
{
int zz = SetSignal (0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C;
if (zz)
{
printf ("\n***BREAK: ^C\n");
}
return (zz);
}
#ifdef __SASC
/*********************************************************************
*
* tell SAS to turn of CTRL-C checking
*/
void __regargs
__chkabort (void)
{
}
#endif
/*********************************************************************
*
* function to use a scsi command
*
*/
int
DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags, BOOLEAN error_report)
{
int i;
io_ptr->io_Length = sizeof (SCSICMD);
io_ptr->io_Data = (APTR) & scsi_cmd;
io_ptr->io_Command = HD_SCSICMD;
scsi_cmd.scsi_Data = (APTR) data;
scsi_cmd.scsi_Length = datasize;
scsi_cmd.scsi_SenseActual = 0;
scsi_cmd.scsi_SenseData = scsi_sense;
scsi_cmd.scsi_SenseLength = SENSE_LEN;
scsi_cmd.scsi_Command = cmd;
scsi_cmd.scsi_CmdLength = cmdsize;
scsi_cmd.scsi_Flags = flags;
(void) DoIO ((struct IORequest *) io_ptr);
if (scsi_cmd.scsi_SenseActual && error_report)
{
fprintf (stderr, "SENSE_DATA:");
for (i = 0; i < scsi_cmd.scsi_SenseActual; i++)
{
fprintf (stderr, " %02x", scsi_cmd.scsi_SenseData[i]);
}
fprintf (stderr, "\n");
}
return (io_ptr->io_Error);
}
/*********************************************************************
*
* function to return an error string
*
*
*/
UBYTE *
err_str (int err)
{
static UBYTE *errors[] =
{
" cannot issue SCSI command to self ",
" DMA error ",
" illegal or unexpected SCSI phase ",
" SCSI parity error ",
" Select timed out ",
" status and/or sense error "
};
err -= 40;
if ((err < 0) || (err > 5))
return ("Error out-of-range");
else
return (errors[err]);
}
/*********************************************************************
*
* usage function
*
*
*/
void
usage (void)
{
static char *zz[] =
{
"Usage: TandbergConf [UNIT] unit [DEVICE devname] [RAW] [RETENSION | AUTOLOAD] [SAVE] [QUIET]\n",
" where:\n",
" unit = (Required) SCSI unit number of Tandberg tape drive\n",
" devname = SCSI device name (Default scsi.device)\n",
" RAW = Show configuration in hex mode(Default, text mode)\n",
" RETENSION = Retension tape when inserted or on reset\n",
" AUTOLOAD = Position tape at load point when inserted or on reset\n",
" SAVE = Make changes permanant (Default, temporary)\n",
" QUIET = Do not print configuration(s)\n",
"" /* TERM */
};
int j = 0;
fprintf (stderr, "TandbergConf V%s [%s : %s] - written by Dave Lowrey\n",
VERSION, __DATE__, __TIME__, pname);
while (*zz[j++])
fprintf (stderr, "%s", zz[j - 1]);
}
/*********************************************************************
*
* sense_errs function ; prints sense errors
*
*
*/
UBYTE *
sense_errs (int req, int err)
{
typedef struct
{
BYTE code;
BYTE sense;
UBYTE *ptr;
} S_ERRS;
/*
* only the likely, interesting ones filled in, e.g media errors
*/
static S_ERRS x[] =
{
0x00, 0x00, "No error",
0x01, 0x04, "?",
0x02, 0x04, "?",
0x03, 0x04, "?",
0x04, 0x02, "?",
0x06, 0x04, "?",
0x09, 0x04, "?",
0x10, 0x03, "?",
0x10, 0x04, "?",
0x11, 0x03, "?",
0x12, 0x03, "?",
0x13, 0x03, "?",
0x14, 0x03, "?",
0x15, 0x04, "Seek error ",
0x17, 0x01, "?",
0x18, 0x01, "?",
0x19, 0x03, "?",
0x1A, 0x05, "?",
0x20, 0x05, "Invalid command op code",
0x21, 0x05, "Illegal sector address",
0x24, 0x05, "?",
0x25, 0x05, "Invalid LUN",
0x26, 0x05, "Invalid field in parameter list",
0x29, 0x06, "?",
0x2A, 0x06, "?",
0x31, 0x03, "?",
0x32, 0x01, "?",
0x32, 0x03, "?",
0x40, 0x04, "?",
0x41, 0x04, "?",
0x42, 0x04, "Power-on diagnostic failure",
0x43, 0x04, "?",
0x45, 0x04, "Select / reselect failure ",
0x47, 0x04, "SCSI Interface Parity Error",
0x48, 0x0B, "?",
0x49, 0x0B, "Illegal message drive can't support",
-1, -1, "ILLEGAL sense!!"
};
int j = 0;
UBYTE *p;
char sense;
char code;
/*
* verify that sense data looks valid
*/
if (((scsi_cmd.scsi_Status & 2) == 0) ||
(scsi_cmd.scsi_SenseActual < OFFS_KEY))
{
return ("");
}
sense = scsi_cmd.scsi_SenseData[OFFS_KEY] & 0xF;
code = scsi_cmd.scsi_SenseData[OFFS_CODE];
do
{
p = x[j].ptr;
if ((x[j].code == code) && (x[j].sense == sense))
break;
} while (x[j++].code != -1);
return (p);
}
void parse_mode()
{
/* printf("Density: ");
if(scsi_data[4] == 0x00)
printf("Default\n");
else if (scsi_data[4] == 0x0f)
printf("QIC-120\n");
else if (scsi_data[4] == 0x10)
printf("QIC-150\n");
else
printf("Unknown\n");
*/
printf("Load Function: ");
if (scsi_data[22] == 0x00)
printf("AUTOLOAD\n");
else if (scsi_data[22] == 0x01)
printf("RETENSION\n");
else
printf("Unknown\n");
}